﻿using System.Collections;

namespace HossMvp.Core
{
    public abstract class AbstractPresenter : IPresenter<AbstractModelManager, AbstractViewManager>
    {
        public class ModelAction : ContentAction
        {
            protected internal ModelAction(string name, AbstractModel model)
                : base(name, model.Contents)
            {
            }
        }

        public class ViewAction : ContentAction
        {
            protected internal ViewAction(string name, AbstractView view)
                : base(name, view.Contents)
            {
            }
        }

        protected AbstractPresenter(AbstractModelManager models, AbstractViewManager views, ICommandProcessor commandProcessor)
        {
            this.CommandProcessor = commandProcessor;
            this.ModelManager = models;
            this.ModelManager.Presenter = this;
            this.ViewManager = views;
            this.ViewManager.Presenter = this;
        }

        public ICommandProcessor CommandProcessor { get; private set; }

        public AbstractModelManager ModelManager { get; private set; }

        public AbstractViewManager ViewManager { get; private set; }

        public abstract class AbstractAction
        {
            protected readonly string name;
            public ActionContext Context { get; private set; }

            public ActionResult Result { get; set; }

            protected AbstractAction(string name, IContentProvider receiver)
            {
                this.name = name;
                this.Context = new ActionContext { Receiver = receiver };
                this.Result = new ActionResult();
            }

            public abstract ActionResult Execute();
        }

        public abstract class ContentAction : AbstractAction
        {
            protected ContentAction(string name, IContentProvider receiver)
                : base(name, receiver)
            {
            }

            public override ActionResult Execute()
            {
                this.Result = this.Context.Receiver.ExecuteAction(this.name, this.Context);
                return this.Result;
            }
        }
    }

    public static class ContentActionFuentApi
    {
        public static AbstractPresenter.ContentAction Action(this AbstractView view, string name)
        {
            var action = new AbstractPresenter.ViewAction(name, view);
            return action;
        }

        public static AbstractPresenter.ContentAction Action(this AbstractModel model, string name)
        {
            var action = new AbstractPresenter.ModelAction(name, model);
            return action;
        }

        public static AbstractPresenter.ContentAction WithPresenter(this AbstractPresenter.ContentAction action, AbstractPresenter presenter)
        {
            action.Context.Presenter = presenter;
            return action;
        }

        public static AbstractPresenter.ContentAction WithSender(this AbstractPresenter.ContentAction action, IContentProvider sender)
        {
            action.Context.Sender = sender;
            return action;
        }

        public static AbstractPresenter.ContentAction WithArguments(this AbstractPresenter.ContentAction action, Hashtable data)
        {
            foreach (string name in data.Keys)
            {
                action.Context.Arguments[name] = data[name];
            }

            return action;
        }

        public static AbstractPresenter.ContentAction WithArgument(this AbstractPresenter.ContentAction action, string name, object value)
        {
            action.Context.Arguments[name] = value;
            return action;
        }
    }
}